/*
 * Copyright 2007. Mount Sinai Hospital, Toronto, Canada.
 * 
 * Licensed under the GNU Lesser General Public License, Version 2. You
 * can find a copy of the license at:
 * 
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
 * 
 * IN NO EVENT SHALL MOUNT SINAI HOSPITAL BE LIABLE TO ANY PARTY FOR DIRECT, 
 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 
 * PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, 
 * EVEN IF MOUNT SINAI HOSPITAL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
 * DAMAGE.
 * 
 * MOUNT SINAI HOSPITAL SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND 
 * ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". 
 * MOUNT SINAI HOSPITAL HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, 
 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
 */
package com.sinai.mshab.client.ui.basic;

import java.util.ArrayList;
import java.util.Iterator;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Widget;
import com.sinai.mshab.client.util.Answer;
import com.sinai.mshab.client.services.ServiceAsync;
import com.sinai.mshab.client.ui.FormComponent;
import com.sinai.mshab.client.ui.aggregate.DataReceiver;
import com.sinai.mshab.client.ui.aggregate.FormData;

/**
 * This component will present the user with a dropdown list of choices.
 * 
 * @author serge
 * 
 */
public class DropDownChoiceComponent extends BasicFormComponent {

	/**
	 * The actual GWT {@link ListBox} (drop down).
	 */
	private ListBox dropdown;

	/**
	 * The list of choices for the drop down.
	 */
	private String choices[];

	/**
	 * Create a new <code>DropDownChoiceComponent</code> with no labels.
	 * 
	 * @param dbfieldName
	 *            the name of the field in the database table where this widget
	 *            stores information.
	 * @param tableName
	 *            the name of the database table where this widget stores
	 *            information.
	 * @param choices
	 *            a list of choices the user can select.
	 */
	public DropDownChoiceComponent(String fieldName, String tableName,
			String choices[]) {
		initializeWidget(fieldName, tableName, null, null, null, choices, true);
	}

	/**
	 * Create a new <code>DropDownChoiceComponent</code> with no labels.
	 * 
	 * @param dbfieldName
	 *            the name of the field in the database table where this widget
	 *            stores information.
	 * @param tableName
	 *            the name of the database table where this widget stores
	 *            information.
	 * @param description
	 *            The description label attached to this widget.
	 * @param choices
	 *            a list of choices the user can select.
	 */
	public DropDownChoiceComponent(String fieldName, String tableName,
			String description, String choices[]) {
		initializeWidget(fieldName, tableName, description, null, null,
				choices, true);
	}

	/**
	 * Create a new <code>DropDownChoiceComponent</code> with the parameters
	 * provided.
	 * 
	 * @param dbfieldName
	 *            the name of the field in the database table where this widget
	 *            stores information.
	 * @param tableName
	 *            the name of the database table where this widget stores
	 *            information.
	 * @param description
	 *            The description label attached to this widget.
	 * @param quantifier
	 *            The quantifier label attached to this widget.
	 * @param choices
	 *            a list of choices the user can select.
	 * @param quantifier
	 *            The quantifier label that goes after textbox (eg. /years)
	 */
	public DropDownChoiceComponent(String fieldName, String tableName,
			String description, String quantifier, String choices[]) {
		initializeWidget(fieldName, tableName, description, quantifier, null,
				choices, true);
	}

	/**
	 * Create a new <code>DropDownChoiceComponent</code> with the parameters
	 * provided.
	 * 
	 * @param dbfieldName
	 *            the name of the field in the database table where this widget
	 *            stores information.
	 * @param tableName
	 *            the name of the database table where this widget stores
	 *            information.
	 * @param description
	 *            The description label attached to this widget.
	 * @param quantifier
	 *            The quantifier label attached to this widget.
	 * @param choices
	 *            a list of choices the user can select.
	 * @param horizontal
	 *            whether or not the dropdown goes under the label or not.
	 */
	public DropDownChoiceComponent(String fieldName, String tableName,
			String description, String quantifier, String choices[],
			boolean horizontal) {
		initializeWidget(fieldName, tableName, description, quantifier, null,
				choices, horizontal);
	}

	/**
	 * Create a new <code>DropDownChoiceComponent</code> with the parameters
	 * provided.
	 * 
	 * @param dbfieldName
	 *            the name of the field in the database table where this widget
	 *            stores information.
	 * @param tableName
	 *            the name of the database table where this widget stores
	 *            information.
	 * @param description
	 *            The description label attached to this widget.
	 * @param quantifier
	 *            The quantifier label attached to this widget.
	 * @param error_msg
	 *            The error message that gets displayed if the attached
	 *            validators do not pass
	 * @param choices
	 *            a list of choices the user can select.
	 */
	public DropDownChoiceComponent(String fieldName, String tableName,
			String description, String quantifier, String error_msg,
			String choices[]) {
		initializeWidget(fieldName, tableName, description, quantifier,
				error_msg, choices, true);
	}

	/**
	 * Create a new <code>DropDownChoiceComponent</code> with the parameters
	 * provided.
	 * 
	 * @param dbfieldName
	 *            the name of the field in the database table where this widget
	 *            stores information.
	 * @param tableName
	 *            the name of the database table where this widget stores
	 *            information.
	 * @param description
	 *            The description label attached to this widget.
	 * @param quantifier
	 *            The quantifier label attached to this widget.
	 * @param error_msg
	 *            The error message that gets displayed if the attached
	 *            validators do not pass
	 * @param choices
	 *            a list of choices the user can select.
	 * @param horizontal
	 *            whether or not the dropdown goes under the label or not.
	 */
	public DropDownChoiceComponent(String fieldName, String tableName,
			String description, String quantifier, String error_msg,
			String choices[], boolean horizontal) {
		initializeWidget(fieldName, tableName, description, quantifier,
				error_msg, choices, horizontal);
	}

	private void initializeWidget(String fieldName, String tableName,
			String description, String quantifier, String error_msg,
			String[] choices, boolean horizontal) {

		// init the dropdown with choices
		initializeDropdown(description, choices);

		this.choices = choices;

		super.initialize(fieldName, tableName, description, quantifier,
				error_msg, dropdown, horizontal);
	}

	private void initializeDropdown(String description, String[] choices) {
		dropdown = new ListBox();

		// Hook up a listener to find out when it's clicked.
		dropdown.addClickListener(new MyListener());

		dropdown.setTitle(description);
		dropdown.addClickListener(new MyListener());

		dropdown.setStyleName("drop_down");
		dropdown.addFocusListener(this);

		// adding the choices
		for (int i = 0; i < choices.length; i++) {
			dropdown.addItem(choices[i]);
		}

		// adding alt
		dropdown.setTitle(description);
	}

	public void sendAnswer(DataReceiver receiver) {
		receiver.sendData(getAnswer());
	}

	public Answer getAnswer() {
		Answer answer = new Answer();

		String value = getSelectedText();
		answer.add(tableName, dbfieldName, value);
		answer.add(hiddenFields);
		return answer;
	}

	/**
	 * When to focus is lost validate the field.
	 */
	public void onFocus(Widget sender) {
		String name = dropdown.getStyleName();
		dropdown.setStyleName(name + "_focus");
	}

	/**
	 * When to focus is lost validate the field.
	 */
	public void onLostFocus(Widget sender) {

		String name = dropdown.getStyleName();
		if (name.indexOf("_focus") != -1) {
			dropdown.setStyleName(name.substring(0, name.length()
					- "_focus".length()));
		}
	}

	public boolean setAnswer(String answer) {
		boolean result = false;

		for (int i = 0; i < dropdown.getItemCount(); i++) {
			if (dropdown.getItemText(i).equals(answer)) {
				dropdown.setSelectedIndex(i);
				result = true;
				break;
			}
		}
		return result;
	}

	public boolean setText(String answer) {
		return setAnswer(answer);
	}

	/**
	 * Sets custom style
	 * 
	 * @param style
	 */
	public void setLabelStyle(String style) {
		subquestion = true;
		description_label.setStyleName(style);
	}

	public Object clone() {
		DropDownChoiceComponent a;
		a = new DropDownChoiceComponent(dbfieldName, tableName, description,
				quantifier, error_msg, choices, horizontal);

		if (subquestion)
			a.setAsSubQuestion();

		return a;
	}

	/**
	 * Populate this widget with FormData using an Answer object
	 * 
	 * @param answer
	 *            the answer object containing the data.
	 */
	public boolean populate(Answer answer) {
		if (answer == null) {
			return false;
		}

		// walking through all the fields-values of answer
		Iterator field_names = answer.getHashMap().keySet().iterator();
		while (field_names.hasNext()) {
			String field_name = (String) field_names.next();

			// if field name matches our widget's field name, use this value
			if (field_name.equalsIgnoreCase(dbfieldName)) {
				String value = (String) answer.getHashMap().get(field_name);

				// going through the items of the dropdown and setting to true
				// the right value.
				boolean success = false;
				for (int j = 0; value != null && j < dropdown.getItemCount(); j++) {
					String current = dropdown.getItemText(j);
					boolean matches = current.equalsIgnoreCase(value);
					dropdown.setItemSelected(j, matches);
					if (matches) {
						success = true;
					}
				}
				return success;

			}
		}
		return false;
	}

	/**
	 * Populate this widget with FormData
	 */
	public boolean populate() {
		Answer a = FormData.getData(tableName);
		return populate(a);
	}

	/**
	 * @see FormComponent#isEmpty()
	 */
	public boolean isEmpty() {

		// get the index of the selected choice and get it's text
		String answer = getSelectedText();

		return answer.equals("");
	}

	/**
	 * Returns the text of the selected item.
	 * 
	 * @return the text of the selected item.
	 */
	private String getSelectedText() {
		int index = dropdown.getSelectedIndex();
		String answer = dropdown.getItemText(index);
		return answer;
	}

	public HorizontalPanel toReport() {

		String answer = getSelectedText();

		// send it off to BasicFormComponent.
		return super.toPrint(answer);
	}

	/**
	 * Informs observers of change to this widget.
	 */
	private class MyListener implements ClickListener {
		public void onClick(Widget sender) {
			notifyObservers(DropDownChoiceComponent.this);
		}
	}

	/**
	 * Sets the style of the dropdown
	 * 
	 * @param string
	 *            the new style name
	 */
	public void setDropDownStyle(String string) {
		dropdown.setStyleName(string);
	}

	/**
	 * This will fill the drop down with choices stored in the database under
	 * the specified column and table name of this widget.
	 */
	public void populateChoicesFromDb() {
		ServiceAsync service = FormData.getInstance().getService();
		service.getSuggestions(this.dbfieldName, this.tableName, "",
				new PopulatedCallback());
	}

	private class PopulatedCallback implements AsyncCallback {

		public void onFailure(Throwable caught) {
		}

		public void onSuccess(Object result) {
			ArrayList results = (ArrayList) result;

			// append the results as choices.
			choices = new String[results.size()];
			dropdown.clear();
			for (int i = 0; i < results.size(); i++) {
				choices[i] = (String) results.get(i);
				dropdown.addItem((String) results.get(i));
			}
		}
	}
}
